/*******************************************************************************
 * Copyright (c) 2018, 2025 Lablicate GmbH.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 * 
 * Contributors:
 * Lorenz Gerber - initial API and implementation, prediction
 * Philip Wenig - refactoring
 *******************************************************************************/
package org.eclipse.chemclipse.xxd.process.supplier.pca.core.algorithms;

import org.eclipse.chemclipse.xxd.process.supplier.pca.exception.MathIllegalArgumentException;
import org.eclipse.chemclipse.xxd.process.supplier.pca.model.AbstractMultivariateCalculator;
import org.ejml.data.DMatrixRMaj;
import org.ejml.dense.row.CommonOps_DDRM;
import org.ejml.dense.row.SingularOps_DDRM;
import org.ejml.dense.row.factory.DecompositionFactory_DDRM;
import org.ejml.interfaces.decomposition.SingularValueDecomposition;

public class CalculatorSVD extends AbstractMultivariateCalculator {

	static final int SEED = 10;

	public CalculatorSVD(int numObs, int numVars, int numComps, int numPredictionSamples) throws MathIllegalArgumentException {

		super(numObs, numVars, numComps, numPredictionSamples);
		DMatrixRMaj emptyLoadings = new DMatrixRMaj(1, numVars);
		setLoadings(emptyLoadings);
	}

	@Override
	public void compute() {

		replaceZeroColsWithSmallRandom();
		computeLoadings();
		computeScores();
		setComputeSuccess();
	}

	private void computeLoadings() {

		SingularValueDecomposition<DMatrixRMaj> svd = DecompositionFactory_DDRM.svd(getSampleData().getNumRows(), getSampleData().getNumCols(), false, true, false);
		svd.decompose(getSampleData());
		setLoadings(svd.getV(null, true));
		DMatrixRMaj W = svd.getW(null);
		SingularOps_DDRM.descendingOrder(null, false, W, getLoadings(), true);
		getLoadings().reshape(getNumComps(), getSampleData().getNumCols(), true);
	}

	private void computeScores() {

		DMatrixRMaj sample = getSampleData().copy();
		DMatrixRMaj rotated = new DMatrixRMaj(getNumComps(), getSampleData().getNumRows());
		DMatrixRMaj loadings = new DMatrixRMaj(getLoadings());
		CommonOps_DDRM.transpose(sample);
		CommonOps_DDRM.mult(loadings, sample, rotated);
		CommonOps_DDRM.transpose(rotated);
		setScores(rotated);
	}
}
